package com.learning.servlet2x.request;

import nl.bitwalker.useragentutils.Browser;
import nl.bitwalker.useragentutils.OperatingSystem;
import nl.bitwalker.useragentutils.UserAgent;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.security.Principal;
import java.util.Enumeration;
import java.util.Locale;


/**
 * ClassName: RequestServlet
 * Description: Servlet 请求
 * 1、请求对象 HttpServletRequest
 * 2、配置 Web.xml
 * 3、调用(PostMan) http://localhost:8080/requestServlet?param=query
 * Date: 2014-9-26 10:30 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class RequestServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doService(request);

    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doService(request);
    }

    /**
     * 通用业务方法
     *
     * @param request 请求对象
     * @throws UnsupportedEncodingException
     * @throws UnknownHostException
     * @throws SocketException
     */
    private void doService(HttpServletRequest request) throws IOException {
        final Object requestParam = request.getAttribute("param");
        System.out.println("request scope param: " + requestParam);


        /** 1-编码方法 ************************************************************************/

        // 1-设置编码方式，可以用时setCharacterEncodingFilter过滤器统一处理
        // 设置获取 request 的编码方式
        String characterEncoding = request.getCharacterEncoding();
        request.setCharacterEncoding("UTF-8");
        // 获取 请求内容类型
        String contentType = request.getContentType();
        System.out.println("编码方式: " + characterEncoding + "| 请求内容类型: " + contentType);


        /** 2-获取服务器信息 ********************************************************************/
        this.getServerInfo(request);


        /** 3-获取客户端信息 *********************************************************************/
        this.getClientInfo(request);


        /** 4-获取请求信息 *********************************************************************/

        // 4-1 获取本次请求的协议信息
        // 协议，这里为HTTP协议
        String protocol = request.getProtocol();
        // 协议头，这里为Http
        String scheme = request.getScheme();
        System.out.println("协议: " + protocol + " | 协议头: " + scheme);

        // 获取请求头信息
        this.getHeader(request);

        // 4-3 获取本次请求的一些基本信息
        // 访问的方式：Get还是Post
        String method = request.getMethod();
        // 查询字符串，即访问时 ？ 后面的字符串
        String queryString = request.getQueryString();
        // 用户请求的URI
        String requestURI = request.getRequestURI();
        // 用户请求的URL
        StringBuffer requestURL = request.getRequestURL();
        System.out.println("访问的方式: " + method + " |查询字符串，即访问时 ？ 后面的字符串: " + queryString + " |用户请求的URI: " + requestURI + " |用户请求的URL: " + requestURL);

        // 4-4 获取请求的Servlet的信息
        // Context路径
        String contextPath = request.getContextPath();
        // Servlet的路径
        String servletPath = request.getServletPath();
        // URL中Servlet路径之后、查询字符串之前的那部分。
        String pathInfo = request.getPathInfo();
        // 映射到服务器实际路径之后的路径信息。
        String pathTranslated = request.getPathTranslated();


        /** 5-其他信息 *********************************************************************/
        // 5-1 其他信息
        // Authorization头, 权限认证的时候使用，一般不会自己用（这是一套标准）。
        // 像Spring Security、apache Shiro 等权限认证框架都会用到
        String authType = request.getAuthType();
        // 当前授权用户的名称
        Principal userPrincipal = request.getUserPrincipal();

        // 客户端Session的ID
        String requestedSessionId = request.getRequestedSessionId();
        // 获取Session信息
        HttpSession session = request.getSession();
        //获取CooKie信息
        Cookie[] cookies = request.getCookies();
        // 本Servlet运行的服务器信息
        String serverInfo = this.getServletContext().getServerInfo();

        System.out.println("Context路径: " + contextPath + " |Servlet的路径: " + servletPath + " |本Servlet运行的服务器信息: " + serverInfo + " |客户端Session的ID: " + requestedSessionId);


        // 绝对路径
        String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + contextPath + "/";
        System.out.println("绝对路径: " + basePath);
    }

    /**
     * 获取请求头信息
     *
     * @param request
     */
    private void getHeader(HttpServletRequest request) {
        // 4-2 获取头信息 利用浏览器都可以看到
        // 浏览器支持的格式,访问Accept的HTTP头
        String accept = request.getHeader("accept");
        // 从哪个页面单机链接到了本页
        String referer = request.getHeader("referer");

        // 包括操作系统及版本号、浏览器类型及版本号
        String host = request.getHeader("Host");
        String acceptLanguage = request.getHeader("Accept-Language");
        String acceptEncoding = request.getHeader("Accept-Encoding");
        String connection = request.getHeader("Connection");
        String cookie = request.getHeader("Cookie");

        // User Agent 信息
        String userAgentStr = request.getHeader("user-agent");

        System.out.println("浏览器支持的格式: " + getAccept(accept) + " |从哪个页面单机链接到了本页: " + referer + " |操作系统信息: " + getOS(userAgentStr) + " |客户端浏览器信息 " + getNavigator(userAgentStr));

        // 使用开源的 UserAgentUtils 工具包
        UserAgent userAgent = UserAgent.parseUserAgentString(userAgentStr);
        Browser browser = userAgent.getBrowser();
        System.out.println("浏览器信息 : " + browser);
        OperatingSystem operatingSystem = userAgent.getOperatingSystem();
        System.out.println("操作系统信息： " + operatingSystem);
    }

    /**
     * 获取客户端基本信息
     *
     * @param request
     */
    private void getClientInfo(HttpServletRequest request) {
        // 远程IP，即客户端IP
        String remoteAddr = request.getRemoteAddr();
        // 远程端口，即客户端端口
        int remotePort = request.getRemotePort();
        // 远程用户,如果提供了Authorization头，则代表其用户部分。它代表发出请求的用户的名字。
        String remoteUser = request.getRemoteUser();
        System.out.println("客户端IP: " + remoteAddr + " |客户端端口: " + remotePort + " |远程用户: " + remoteUser);

        // 客户端的IP，往往会有代理，所以一般的获取方法，需要处理信息
        //真实客户端IP地址
        String realCusIp = getRealCusIpAddr(request);
        System.out.println("客户端真实IP，附带代理的IP地址： " + realCusIp);
    }

    /**
     * 获取服务器信息
     *
     * @param request
     * @throws UnknownHostException
     */
    private void getServerInfo(HttpServletRequest request) throws UnknownHostException {
        // 2-0-基本的获取服务器信息

        // 本地IP, 即服务器IP
        String localAddr = request.getLocalAddr();
        // 本地名称, 即服务器名称
        String localName = request.getLocalName();
        // 本地端口号, 即服务器端口号
        int localPort = request.getLocalPort();
        // 本地环境，服务器环境.通过这个可以获取很多信息
        Locale locale = request.getLocale();
        // 语言环境
        String localeLanguage = this.getLocaleLanguage(locale);
        // 国家
        String localCountry = locale.getCountry();
        System.out.println(" |服务器IP: " + localAddr + " |服务器名称: " + localName + " |端口号: " + localPort + " |用户的语言环境: " + localeLanguage + " |国家: " + localCountry);

        // 服务器名称
        String serverName = request.getServerName();
        // 服务器端口
        int serverPort = request.getServerPort();
        System.out.println("服务器名称: " + serverName + " |服务器端口: " + serverPort);

        // 2-1 实际项目中，一般会用到 java.net 包下 InetAddress 来获取服务器的真实 IP 地址
        // 本地地址,服务器IP地址
        String myLocalIp = InetAddress.getLocalHost().getHostAddress();
        System.out.println("利用java.net包下 InetAddress 来获取服务器真实 IP 地址: " + myLocalIp);
        // 2-2 Linux 获取服务器的真实 IP 地址
        String serverIP = getServerIP();
        System.out.println("Linux下 来获取服务器真实 IP 地址: " + serverIP);
    }

    /**
     * linux下获取服务器真实 IP
     * InetAddress获取IP的方法在windows下没有问题，在Linux有问题,主要是在linux下返回的是 /etc/hosts
     * 中配置的ip地址，而不是网卡的绑定地址。现在改用网卡的绑定地址，可以取到本机的ip地址：
     *
     * @return
     */
    public static String getServerIP() {
        String serverIp = "";
        try {
            // InetAddress获取IP的方法在windows下没有问题，在Linux有问题（下只是读取/etc/hosts下的配置）
            Enumeration<NetworkInterface> netInterfaces = null;
            netInterfaces = NetworkInterface.getNetworkInterfaces();
            while (netInterfaces.hasMoreElements()) {
                NetworkInterface ni = netInterfaces.nextElement();
                Enumeration<InetAddress> ips = ni.getInetAddresses();
                while (ips.hasMoreElements()) {
                    InetAddress ip = ips.nextElement();
                    if (ip.isSiteLocalAddress()) {
                        serverIp = ip.getHostAddress();
                        break;
                    }
                }
            }
        } catch (Exception ex) {
            serverIp = "127.0.0.1";
        }
        return serverIp;
    }

    /**
     * 用户的语言环境
     *
     * @param locale
     * @return 语言环境名称
     */
    private String getLocaleLanguage(Locale locale) {
        if (Locale.SIMPLIFIED_CHINESE.equals(locale)) {
            return "简体中文";
        }
        if (Locale.TRADITIONAL_CHINESE.equals(locale)) {
            return "繁体中文";
        }
        if (Locale.ENGLISH.equals(locale)) {
            return "英文";
        }
        if (Locale.JAPANESE.equals(locale)) {
            return "日文";
        }
        return "未知语言环境";
    }

    /**
     * @param accept
     * @return 客户端浏览器接受的文件类型
     */
    private String getAccept(String accept) {
        StringBuffer buffer = new StringBuffer();
        if (accept.contains("image/gif")) {
            buffer.append("GIF 文件, ");
        }
        if (accept.contains("image/x-xbitmap")) {
            buffer.append("BMP 文件, ");
        }
        if (accept.contains("image/jpeg")) {
            buffer.append("JPG 文件, ");
        }
        if (accept.contains("application/vnd.ms-excel")) {
            buffer.append("Excel 文件, ");
        }
        if (accept.contains("application/vnd.ms-powerpoint")) {
            buffer.append("PPT 文件, ");
        }
        if (accept.contains("application/msword")) {
            buffer.append("Word 文件, ");
        }
        return buffer.toString().replaceAll(", $", "");
    }

    /**
     * 客户端浏览器信息
     *
     * @param userAgent
     * @return String
     */
    private String getNavigator(String userAgent) {
        if (userAgent.indexOf("TencentTraveler") > 0) {
            return "腾讯浏览器";
        }
        if (userAgent.indexOf("Maxthon") > 0) {
            return "Maxthon浏览器";
        }
        if (userAgent.indexOf("MyIE2") > 0) {
            return "MyIE2浏览器";
        }
        if (userAgent.indexOf("Firefox") > 0) {
            return "Firefox浏览器";
        }
        if (userAgent.indexOf("MSIE") > 0) {
            return "IE 浏览器";
        }
        if (userAgent.indexOf("Chrome") > 0) {
            return "Chrome 浏览器";
        }
        return "未知浏览器";
    }

    /**
     * 客户端操作系统
     *
     * @param userAgent
     * @return String
     */
    private String getOS(String userAgent) {
        if (userAgent.indexOf("Windows NT 5.1") > 0) {
            return "Windows XP";
        }
        if (userAgent.indexOf("Windows 98") > 0) {
            return "Windows 98";
        }
        if (userAgent.indexOf("Windows NT 5.0") > 0) {
            return "Windows 2000";
        }
        if (userAgent.indexOf("Linux") > 0) {
            return "Linux";
        }
        if (userAgent.indexOf("Unix") > 0) {
            return "Unix";
        }
        if (userAgent.indexOf("Windows NT 6.1") > 0) {
            return "Windows 7";
        }
        if (userAgent.indexOf("Windows NT 10.0") > 0) {
            return "Windows 10";
        }
        return "未知";
    }

    /**
     * 获得用户真实IP
     *
     * @param request 请求对象
     * @return String 真实IP地址
     */
    public String getRealCusIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

/*、
Chrome 查看得出信息
【General】
Request URL: http://localhost:8080/requestServlet?param=query
Request Method: GET
Status Code: 200
Remote Address: [::1]:8080
Referrer Policy: no-referrer-when-downgrade

【Request Headers】
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng, ;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7
Cache-Control: max-age=0
Connection: keep-alive
Cookie: jenkins-timestamper-offset=-28800000; Idea-e846873f=b0ad7d26-ab1f-4b0f-95cb-0ed1c50bf3d9; locale=zh; rememberMe=xd5Owi0OZblXMRYwdSLv2IoYw95yvOxQqFjw4g9mTxEFL6Htj9Jpamucwg3XkbE04pSFUwUL7jgVEsy3aV7ispSBptVMFUvvUW2//5x3Rg0yKWdaGrTl6wCTEaxOUxUG7Qh2bAiyy/bjPjt1kCDPWfUCa5MrT05gSMyTI7s2ix5CMswL3QW2nu4R0Bvw4pY3YaQQ4zE4/oxaR7o1x5PF4iLQg6yyl7PP4Ce/Fh/U3rKsr3YE+f68mwD+7/kfyq1V6LSwdrdaTOKGs3fB8ke3y16AA26MD1W9aRwIx8RqxF6W5N14XQ8oqtpg98jrHW5pRK+wOCm9Xb4dQPUesriARNP0FbHULwh2w5S1ytU26eUDU2rpnLgsweDNE12ImR3i/7ez7/Fguidrk+soWD1qGJYKqeYyqN6B1ihAhN/umw0WM9PCuQUBTtLBndoCPgeDWU912rTlAwrsvO1sB0G7RmLpKz6poenYDPQ5Mb0KEMIZPNfxHo+TKekbwRsGJS1hhnlmYOxY3ABS6iGUrOQGSZeGdH4bBeNT1s194cO/n6Y31xiVks0MPhFuEnATFE7jEqi3oZSrNPHjybPU9ee7DtRyQZTVrKADOtydfOltGB/wV2s+8m4OmyWDWX+m+gRXaeiFqkDNMb5Rhee3iQoh/m4jBOfYjAK/3BG7+7svCWGMazRXO6Zs4GcmYMWpXzoKlz0weQFOaek1zP6124zjS1968YKHCpRnTVYULvrtM7C/3kQysR4TUm5JnyrtbSrdznrvsC8jTmsvnAwVV8FJJH8FKkYuaUHIAIJs+w3kxiHNf7ibAbyp3muXroE+Bg7I; Hm_lvt_82116c626a8d504a5c0675073362ef6f=1528939560,1528957763,1529377607,1529379542; _ga=GA1.1.600775327.1529394240; Hm_lvt_df863698d6887525c609d6e464867778=1529551688,1529584292; JSESSIONID=6BA33CCE37F788B54EA0A063A4E2CB31
Host: localhost:8080
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36

【Query String Parameters】
param: query

 */
